home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / c / db / RCS / DbLockDesc.c,v < prev   
Text File  |  1989-11-05  |  10KB  |  455 lines

  1. head     1.7;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.7
  10. date     89.07.31.17.42.10;  author douglis;  state Exp;
  11. branches ;
  12. next     1.6;
  13.  
  14. 1.6
  15. date     89.06.15.22.45.35;  author douglis;  state Exp;
  16. branches ;
  17. next     1.5;
  18.  
  19. 1.5
  20. date     89.01.21.16.33.30;  author douglis;  state Exp;
  21. branches ;
  22. next     1.4;
  23.  
  24. 1.4
  25. date     89.01.13.11.42.01;  author douglis;  state Exp;
  26. branches ;
  27. next     1.3;
  28.  
  29. 1.3
  30. date     89.01.05.11.57.07;  author douglis;  state Exp;
  31. branches ;
  32. next     1.2;
  33.  
  34. 1.2
  35. date     89.01.04.21.03.00;  author douglis;  state Exp;
  36. branches ;
  37. next     1.1;
  38.  
  39. 1.1
  40. date     88.09.21.14.07.31;  author douglis;  state Exp;
  41. branches ;
  42. next     ;
  43.  
  44.  
  45. desc
  46. @Procedure to lock a file descriptor, optionally polling or breaking
  47. the lock.
  48. @
  49.  
  50.  
  51. 1.7
  52. log
  53. @reinstated code to break lock on behalf of other process
  54. @
  55. text
  56. @/* 
  57.  * DbLockDesc.c --
  58.  *
  59.  *    Source code for the DbLockDesc procedure.
  60.  *
  61.  * Copyright 1988 Regents of the University of California
  62.  * Permission to use, copy, modify, and distribute this
  63.  * software and its documentation for any purpose and without
  64.  * fee is hereby granted, provided that the above copyright
  65.  * notice appear in all copies.  The University of California
  66.  * makes no representations about the suitability of this
  67.  * software for any purpose.  It is provided "as is" without
  68.  * express or implied warranty.
  69.  */
  70.  
  71. #ifndef lint
  72. static char rcsid[] = "$Header: /sprite/src/lib/c/db/RCS/DbLockDesc.c,v 1.6 89/06/15 22:45:35 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  73. #endif not lint
  74.  
  75.  
  76. #include <db.h>
  77. #include "dbInt.h"
  78. #include <sys/signal.h>
  79. #include <sys/time.h>
  80. #include <stdio.h>
  81.  
  82. #ifndef CLEAN
  83. int db_Contention = 0;
  84. #endif /* CLEAN */
  85.  
  86. /*
  87.  * Set the default timeout, in seconds.
  88.  */
  89. #ifndef DB_LOCK_TIMEOUT
  90. #define DB_LOCK_TIMEOUT 10
  91. #endif /* DB_LOCK_TIMEOUT */
  92.  
  93. /*
  94.  *----------------------------------------------------------------------
  95.  *
  96.  * AlarmHandler --
  97.  *
  98.  *    Routine to service a SIGALRM signal.  This routine disables
  99.  *    the alarm (letting the caller reenable it when appropriate).
  100.  *
  101.  * Results:
  102.  *    None.
  103.  *
  104.  * Side effects:
  105.  *    The alarm is disabled.
  106.  *
  107.  *----------------------------------------------------------------------
  108.  */
  109. static int
  110. AlarmHandler()
  111. {
  112.     
  113.     alarm(0);
  114. #ifdef DEBUG
  115.     syslog(LOG_INFO, "Database lock timed out.");
  116. #endif /* DEBUG */
  117.     (void) signal (SIGALRM, SIG_IGN);
  118. }
  119.  
  120.  
  121. /*
  122.  *----------------------------------------------------------------------
  123.  *
  124.  * DbLockDesc --
  125.  *
  126.  *    Lock a file descriptor, polling if necessary, and potentially
  127.  *    breaking the lock if timeout occurs.
  128.  *
  129.  * Results:
  130.  *    If the file is locked, by hook or by crook,
  131.  *    0 is returned.  If the file is not successfully locked,
  132.  *    -1 indicates an error and errno gives a more specific error.
  133.  *
  134.  * Side effects:
  135.  *    None.
  136.  *
  137.  *----------------------------------------------------------------------
  138.  */
  139.  
  140. int
  141. DbLockDesc(handlePtr)
  142.     Db_Handle *handlePtr;
  143. {
  144.     int streamID;            /* file descriptor */
  145.     int type;                /* type of lock */
  146.     Db_LockHow action;        /* DB_LOCK_{POLL,BLOCK,NO_BLOCK,WAIT,NONE} */
  147.     int status;
  148.     struct itimerval itimer, oldItimer;
  149.     int (*oldHandler) ();
  150.     int error;
  151.     static int syslogDone = 0;
  152.  
  153.  
  154.     streamID = handlePtr->streamID;
  155.     action = handlePtr->lockHow;
  156.     type = handlePtr->lockType;
  157.     
  158.     if (action == DB_LOCK_NONE) {
  159.     return(0);
  160.     }
  161.     if (action != DB_LOCK_WAIT) {
  162.     type |= LOCK_NB;
  163.     }
  164.     /*
  165.      * Try the lock, then set a timer and try again.
  166.      *
  167.      * If the lock call times out in the RPC, return SUCCESS to keep the caller
  168.      * from aborting.
  169.      */
  170.     
  171.     status = flock(streamID, type);
  172.     if (status == -1) {
  173.     /*
  174.      * It is possible to get a sprite RPC_TIMEOUT condition, or other
  175.      * obscure error, which will map to EINVAL by default.  We're mostly
  176.      * interested in the EWOULDBLOCK condition, so if we get something
  177.      * we know is likely to be innocuous, return 0.  In particular,
  178.      * we don't want our caller to abort because the lock timed out, since
  179.      * it can wait for recovery.
  180.      */
  181.     if (errno == EINVAL) {
  182.         return(0);
  183.     } 
  184.     if ((errno != EWOULDBLOCK) || (action == DB_LOCK_NO_BLOCK)) {
  185.         return(-1);
  186.     }
  187.     } else {
  188.     return(0);
  189.     }
  190.  
  191.     /*
  192.      * Now lock in blocking mode, with an interval timer around to wake
  193.      * us up if need be.
  194.      */
  195. #ifndef CLEAN
  196.     db_Contention++;
  197. #endif
  198.  
  199.     type &= ~LOCK_NB;
  200.     itimer.it_interval.tv_sec = 0;
  201.     itimer.it_interval.tv_usec = 0;
  202.     itimer.it_value.tv_sec = DB_LOCK_TIMEOUT;
  203.     itimer.it_value.tv_usec = 0;
  204.  
  205.     oldHandler = (int (*)()) signal(SIGALRM, AlarmHandler);
  206.     if (oldHandler == (int (*)()) -1) {
  207.     syslog(LOG_ERR, "Error setting signal handler.");
  208.     return(-1);
  209.     }
  210.     if (setitimer(ITIMER_REAL, &itimer, &oldItimer) == -1) {
  211.     error = errno;
  212.     (void) signal(SIGALRM, oldHandler);
  213.     errno = error;
  214.     return(-1);
  215.     }
  216. #ifdef LOCK_DEBUG
  217.     syslog(LOG_INFO, "Debug msg: DB doing blocking lock with timeout.");
  218. #endif
  219.  
  220.     status = flock(streamID, type);
  221.  
  222. #ifdef LOCK_DEBUG
  223.     syslog(LOG_INFO, "Debug msg: blocking lock with timeout returned %d, errno %d.", status, errno);
  224. #endif
  225.  
  226.     error = errno;
  227.     if (setitimer(ITIMER_REAL, &oldItimer, (struct itimerval *) NULL) == -1) {
  228.     return(-1);
  229.     }
  230.     (void) signal(SIGALRM, oldHandler);
  231.     if (status == -1) {
  232.     errno = error;
  233.     if (errno == EINVAL || errno == 0) {
  234.         return(0);
  235.     }
  236.     if (errno != EINTR) {
  237.         return(status);
  238.     }
  239.     if (action == DB_LOCK_POLL) {
  240.         errno = ETIMEDOUT;
  241.         return(-1);
  242.     }
  243. #ifndef CLEAN
  244.     if (!syslogDone) {
  245.         syslog(LOG_INFO, "DbLockDesc: lock timed out (file %s).\n",
  246.            handlePtr->fileName);
  247.         syslogDone = 1;
  248.     }
  249. #endif /* CLEAN */
  250.  
  251.     /*
  252.      * Break the lock if required.  Try to break an exclusive lock.  If
  253.      * that fails, and we were trying to get an exclusive lock, then try
  254.      * releasing a shared lock since that could have been the problem.
  255.      * Then try to get the lock again.
  256.      * Return EWOULDBLOCK if breaking the lock wasn't successful.
  257.      *
  258.      * This has been commented out because one may no longer break
  259.      * locks on behalf of other processes.
  260.      */
  261.     if (action == DB_LOCK_BREAK) {
  262.         status = flock(streamID, LOCK_EX | LOCK_NB | LOCK_UN);
  263.         if ((status != 0) && (type & LOCK_EX)) {
  264.         (void) flock(streamID, LOCK_SH | LOCK_NB | LOCK_UN);
  265.         }
  266.     }
  267.     status = flock(streamID, type | LOCK_NB);
  268.     if (status == 0) {
  269.         return(0);
  270.     } else if (errno != EWOULDBLOCK) {
  271.         return(status);
  272.     } else {
  273. #ifdef CLEAN
  274.         syslog(LOG_WARNING, "DbLockDesc: unable to lock stream %d in %s mode",
  275.            streamID, (type & LOCK_EX) ? "exclusive" : "shared");
  276. #else /* CLEAN */
  277.         syslog(LOG_WARNING, "DbLockDesc: unable to lock file %s in %s mode",
  278.            handlePtr->fileName,
  279.            (type & LOCK_EX) ? "exclusive" : "shared");
  280. #endif /* CLEAN */
  281.     }
  282.  
  283. /*
  284.  * Once this thing is really production quality, it should return an error
  285.  * if the lock times out.  For now, especially as long as processes can go
  286.  * into the debugger with a lock held, just return success anyway.  We
  287.  * tried.
  288.  */
  289.  
  290. #ifdef INSTALLED
  291.     errno = EWOULDBLOCK;
  292.     return (-1);
  293. #else /* INSTALLED */
  294.     return(0);
  295. #endif /* INSTALLED */
  296.     }
  297.     return(0);
  298. }
  299.  
  300.  
  301. @
  302.  
  303.  
  304. 1.6
  305. log
  306. @only print syslog message once
  307. @
  308. text
  309. @d17 1
  310. a17 1
  311. static char rcsid[] = "$Header: /sprite/src/lib/c/db/RCS/DbLockDesc.c,v 1.5 89/01/21 16:33:30 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  312. a195 1
  313. #ifdef notdef
  314. a225 2
  315.         errno = EWOULDBLOCK;
  316.         return (-1);
  317. a226 1
  318. #endif /* notdef */
  319. @
  320.  
  321.  
  322. 1.5
  323. log
  324. @changed order of resetting signal handler and resetting
  325. interval timer to remove race condition.
  326. @
  327. text
  328. @d17 1
  329. a17 1
  330. static char rcsid[] = "$Header: /sprite/src/lib/c/db/RCS/DbLockDesc.c,v 1.4 89/01/13 11:42:01 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  331. d57 5
  332. d151 4
  333. d161 4
  334. d166 5
  335. d178 1
  336. a178 1
  337.     if (errno = EINVAL) {
  338. d192 1
  339. @
  340.  
  341.  
  342. 1.4
  343. log
  344. @changed to take just a handle, which popints to the relevant
  345. info.  fixed bug with locking and then not returning immediately.
  346. @
  347. text
  348. @d17 1
  349. a17 1
  350. static char rcsid[] = "$Header: /sprite/src/lib/c/db/RCS/DbLockDesc.c,v 1.3 89/01/05 11:57:07 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  351. a153 1
  352.     (void) signal(SIGALRM, oldHandler);
  353. d157 1
  354. @
  355.  
  356.  
  357. 1.3
  358. log
  359. @changed to do blocking lock w/ timeout.  
  360. @
  361. text
  362. @d17 1
  363. a17 1
  364. static char rcsid[] = "$Header: /sprite/src/lib/c/db/RCS/DbLockDesc.c,v 1.1 88/09/21 14:07:31 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  365. a56 1
  366.     syslog(LOG_INFO, "DbLockDesc: lock timed out.\n");
  367. d81 3
  368. a83 1
  369. DbLockDesc(streamID, type, action)
  370. a86 1
  371. {
  372. d91 1
  373. d94 4
  374. d170 8
  375. d184 3
  376. d200 1
  377. d202 6
  378. a207 1
  379.        streamID, (type & LOCK_EX) ? "exclusive" : "shared");
  380. d211 15
  381. d229 2
  382. @
  383.  
  384.  
  385. 1.2
  386. log
  387. @fixed what looked like a bug that would cause contention to wait for a 
  388. long time rather than returning the first time the lock succeeded.
  389. @
  390. text
  391. @d23 3
  392. d27 10
  393. d41 24
  394. a86 1
  395.     int delay;
  396. d88 3
  397. a90 4
  398.     int numTries;        /* Counter through the loop polling the lock */
  399.     int numRetries;        /* Counter through a loop retrying in the
  400.                  * event we break the lock and someone else
  401.                  * grabs it. */
  402. d92 1
  403. d100 1
  404. a100 2
  405.      * Try the lock, then loop.  This gets rid of an extraneous delay
  406.      * after the last unsuccessful lock try.
  407. d102 1
  408. a102 1
  409.      * If the lock call times out, return SUCCESS to keep the caller
  410. d126 31
  411. a156 16
  412.     for (numRetries = 0; numRetries < NUM_TRIES; numRetries++) {
  413.     delay = DELAY;
  414.     for (numTries = 0; numTries < NUM_TRIES; numTries++) {
  415.         (void) sleep(delay);
  416.         delay *= 2;
  417.         status = flock(streamID, type);
  418.         if (status == -1) {
  419.         if (errno = EINVAL) {
  420.             return(0);
  421.         }
  422.         if ((errno != EWOULDBLOCK) || (action == DB_LOCK_NO_BLOCK)) {
  423.             return(status);
  424.         }
  425.         } else {
  426.         return(0);
  427.         }
  428. d158 3
  429. d162 2
  430. a163 1
  431.         return(ETIMEDOUT);
  432. d178 1
  433. a178 1
  434.     status = flock(streamID, type);
  435. d183 5
  436. d190 1
  437. a190 4
  438.     syslog(LOG_WARNING, "DbLockDesc: unable to lock stream %d in %s mode",
  439.        streamID, (type & LOCK_EX) ? "exclusive" : "shared");
  440.     errno = EWOULDBLOCK;
  441.     return (-1);
  442. @
  443.  
  444.  
  445. 1.1
  446. log
  447. @Initial revision
  448. @
  449. text
  450. @d17 1
  451. a17 1
  452. static char rcsid[] = "$Header: DbLockDesc.c,v 1.2 88/09/13 16:48:36 douglis Exp $ SPRITE (Berkeley)";
  453. d104 2
  454. @
  455.